﻿using Nirvana;

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Audio;
namespace Nirvana.SoundCommon
{
    /// <summary>
    /// 音效播放组
    /// </summary>
    public enum AudioItemMixerGroup
    {
        /// <summary>
        /// 音乐组：背景音乐
        /// </summary>
        MusicGroup = 1,
        /// <summary>
        /// UI音效组：ui上的点击，弹窗等，优先级1，
        /// </summary>
        UISoundGroup,
        /// <summary>
        /// 玩法音效组：玩法环境音效，优先级2
        /// </summary>
        FuncSoundGroup,
        /// <summary>
        /// 特效音效组：战斗中的子弹，技能，受击等
        /// </summary>
        EffectSoundGroup,
        /// <summary>
        /// 死亡爆炸音效组：战斗死亡爆炸音效，独立出来是避免特效音效组数量最大时，死亡爆炸等音效不播放问题
        /// </summary>
        DieBoomSoundGroup,
    }

    public sealed class AudioSubItemData
    {
        public string audioClipName;
        public AudioClip audioClip;
        public AudioMixerGroup mixerGroup;
        public bool isLoop;
        public float volume;
        public float delay;
        /// <summary>
        /// 优先级:1~4
        /// </summary>
        public int priority;
        public float fadeInTime;
        public float fadeOutTime;
        public float spatialBlend;
        public void Clear()
        {
            this.audioClipName = null;
            this.audioClip = null;
            this.mixerGroup = null;
            this.isLoop = false;
            this.volume = 1f;
            this.delay = 0f;
            this.fadeInTime = 0f;
            this.fadeOutTime = 0f;
            this.spatialBlend = 0;
        }
    }

    /// <summary>
    /// 音效资源对象：每个音效资源可以频繁的创建播放，需要控制播放的间隔和数量，避免同类音效瞬间大量触发，比如死亡，爆炸，受击等。
    /// </summary>
    public class AudioItem
    {
        private AudioMixerGroup mixerGroup;
        private AudioMixerGroupItem audioGroup;

        //最大数量， 0 ：不限制"
        private int maxCount;
        private float interval;
        private float curTime;
        private float delay;
        public float Delay => delay;
        public AudioItemMixerGroup mixerTypeGroup;

        /// <summary>
        /// 当前audio播放数量
        /// </summary>
        private int curPlayerCount;


        public string assetName;


        /// <summary>
        /// 初始化音效管理组item
        /// </summary>
        /// <param name="audioClip">音效资源</param>
        /// <param name="delay">播放延时时间</param>
        public void Init(string assetName, float delay = 0)
        {
            this.delay = delay;
            this.assetName = assetName;

            var config = SoundDataManager.Instance.GetSoundConfig(assetName);
            this.interval = config.interval;
            this.maxCount = config.maxCount;
            this.mixerTypeGroup = config.mixerGroup;
            audioGroup = AudioManager.Instance.GetAudioMixerGroup(mixerTypeGroup);

            this.mixerGroup = audioGroup.mixerGroup;

        }

        public bool IsCanPlay()
        {
            if (Time.realtimeSinceStartup < this.curTime + this.interval)
            {
                return false;
            }
            if (this.maxCount > 0 && this.curPlayerCount >= this.maxCount)
            {
                return false;
            }

            if (this.audioGroup != null)
            {

                return this.audioGroup.IsCanPlay();
            }

            return true;
        }
        public void Play(AudioClip audioClip, string assetName)
        {
            if (!IsCanPlay())
            {
                AudioClipPool.Instance.Free(audioClip, false);
                return;
            }

            var config = SoundDataManager.Instance.GetSoundConfig(assetName);
            var subItem = AudioManager.Instance.PopAudioItem();
            if (subItem == null) subItem = new AudioSubItemData();

            subItem.Clear();
            subItem.audioClip = audioClip;
            subItem.audioClipName = assetName;
            subItem.isLoop = config.isLoop;
            subItem.priority = config.priority;
            subItem.volume = config.volume;
            subItem.fadeInTime = config.fadeInTime;
            subItem.fadeOutTime = config.fadeOutTime;
            subItem.spatialBlend = config.spatialBlend;
            subItem.mixerGroup = mixerGroup;

            PlayAndForget(subItem);
        }

        private void PlayAndForget(AudioSubItemData subItemData)
        {
            var audio = GetPlayerAudio(AudioManager.Instance.AudioPool, subItemData);
            audio.Set(Vector3.zero);
            audio.Play();
            audio.Mute(false);

        }

        private IPlayerAudio GetPlayerAudio(AudioSourcePool pool, AudioSubItemData subItemData)
        {
            if (subItemData == null || subItemData.audioClip == null) return PlayerAudioBasic.Instance;
            this.curPlayerCount++;
            this.curTime = Time.realtimeSinceStartup;
            IPlayerAudio audio = new PlayerAudioDelay(pool, this, subItemData, subItemData.isLoop);

            AudioManager.Instance.playerAudioList.Add(audio);
            if (this.audioGroup != null && audio != PlayerAudioBasic.Instance) this.audioGroup.Add(audio);

            return audio;

        }

        public void InitAudioSource(AudioSource source, AudioSubItemData item)
        {
            source.transform.SetPositionAndRotation(Vector3.zero, Quaternion.identity);
            source.transform.localScale = Vector3.one;
            source.clip = item.audioClip;
            if (item.mixerGroup != null)
            {
                source.outputAudioMixerGroup = item.mixerGroup;
            }
            else
            {
                source.outputAudioMixerGroup = this.mixerGroup;
            }
            source.priority = 128 / item.priority;
            source.volume = item.volume;
            source.spatialBlend = item.spatialBlend;
        }

        public void Remove(IPlayerAudio audio)
        {
            this.curPlayerCount--;

            if (this.audioGroup != null) this.audioGroup.Remove(audio);
            var subdata = audio.GetAudioSubItemData();
            if (subdata != null)
            {
                AudioClipPool.Instance.Free(subdata.audioClip, false);
                subdata.audioClip = null;
                subdata.Clear();
                AudioManager.Instance.PushAudioItem(subdata);
            }
            audio.Dispose();
        }

        public void Dispose()
        {
            audioGroup = null;
            mixerGroup = null;
        }
    }
}